package com.nowcoder.community.controller;

import com.google.code.kaptcha.Producer;
import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.CommunityConstant;
import com.nowcoder.community.util.CommunityUtil;
import com.nowcoder.community.util.MailClient;
import com.nowcoder.community.util.RedisKeyUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>Title: LoginController</p>
 * <p>author 12427</p>
 *
 * @version ver1.0
 * @date 2022/7/6 18:24
 */

@Controller
public class LoginController implements CommunityConstant {

    private static final Logger logger = LoggerFactory.getLogger(LoginController.class) ;

    @Autowired
    private UserService userService ;

    @Autowired
    private Producer kaptchaProducer ;
    @Autowired
    private TemplateEngine templateEngine ;
    @Autowired
    private MailClient mailClient ;

    @Autowired
    private RedisTemplate redisTemplate ;

    @Value("${server.servlet.context-path}")
    private String contextPath ;


    @RequestMapping(path="/register" , method = RequestMethod.GET)
    public  String getRegisterPage(){
        return "site/register";
    }


    @RequestMapping(path="/login" , method = RequestMethod.GET)
    public  String getLoginPage(){
        return "site/login";
    }


    @RequestMapping(path = "/register" , method = RequestMethod.POST)
    public String register(Model model , User user ){
        Map<String,Object> map = userService.register(user) ;
        if(map == null || map.isEmpty()){
            model.addAttribute("msg" , "注册成功,我们已向您的邮箱发送了激活邮件，请查收!") ;
            model.addAttribute("target","index") ;
            return "site/operate-result";
        }
        else {

            model.addAttribute("usernameMsg" , map.get("usernameMsg")) ;
            model.addAttribute("passwordMsg" , map.get("passwordMsg")) ;
            model.addAttribute("emailMsg" , map.get("emailMsg")) ;

            return "site/register" ;
        }
    }
    // http://hocalhost:8080/community/activation/{id}/code
    @RequestMapping(path = "/activation/{userId}/{code}" , method = RequestMethod.GET)
    public String activation(Model model , @PathVariable ("userId") int userId , @PathVariable("code") String code){

        int result = userService.activation(userId, code);

        if(result == ACTIVATION_SUCCESS){
            model.addAttribute("msg" , "激活成功！您的账号可以正常登录了~") ;
            model.addAttribute("target","/login") ;

        }else if(result == ACTIVATION_REPEATE){

            model.addAttribute("msg" , "无效操作,该账号已被激活!") ;
            model.addAttribute("target","/index") ;
        }else {
            model.addAttribute("msg" , "激活失败，您提供的激活码不匹配!") ;
            model.addAttribute("target","/index") ;
        }

        return "site/operate-result";
    }


    // 我们向浏览器输出的是一个图片，而不是一个网页或者是一个字符串，所以返回值是void
    // 我们需要自己用Response对象手动向浏览器输出
    @RequestMapping(path="/kaptcha" , method = RequestMethod.GET)
    public void getKaptcha(HttpServletResponse response ){
        // 生成验证码
        String text = kaptchaProducer.createText() ;
        BufferedImage image = kaptchaProducer.createImage(text);
//        // 验证码存入session
//        session.setAttribute("kaptcha" , text);

        // 存储在redis里
        // 验证码的归属
        String kaptchaOwner = CommunityUtil.generateUUID() ;
        Cookie cookie = new Cookie("kaptchaOwner" , kaptchaOwner ) ;
        cookie.setMaxAge(60);
        cookie.setPath(contextPath);
        response.addCookie(cookie);
        // 将验证码存入redis
        String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner) ;
        redisTemplate.opsForValue().set(redisKey , text  , 60 , TimeUnit.SECONDS);


        // 将图片输出给浏览器
        response.setContentType("image/png");
        try {
            OutputStream os = response.getOutputStream();
            ImageIO.write(image,"png" , os) ;
        } catch (IOException e) {
            logger.error("响应验证码失败" + e.getMessage()) ;
        }
    }


    @RequestMapping(path = "/login" , method = RequestMethod.POST)
    public String login(String username , String password , String code,
                        boolean rememberMe , Model model ,HttpServletResponse response  , @CookieValue("kaptchaOwner") String kaptchaOwner) {
        // 先判断验证码
//        String kaptcha = (String) session.getAttribute("kaptcha") ;
        String kaptcha = null ;
        if(StringUtils.isNoneBlank(kaptchaOwner)){
            String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner) ;
            kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
        }

        if(StringUtils.isBlank(kaptcha ) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
            model.addAttribute("codeMsg" , "验证码不正确") ;
            return "/site/login" ;
        }

        // 检查账号的密码
        int expiredSeconds = rememberMe?REMEMBER_EXPIRED_SECONDS:DEFAULT_EXPIERED_SECONDS ;
        Map<String, Object> map = userService.login(username, password, expiredSeconds);

        // 成功
        if(map.containsKey("ticket")){

            Cookie cookie = new Cookie("ticket" , map.get("ticket").toString()) ;
            cookie.setPath(contextPath);
            cookie.setMaxAge(expiredSeconds);
            response.addCookie(cookie);
            return "redirect:/index" ;
        }else {
            model.addAttribute("usernameMsg" , map.get("usernameMsg")) ;
            model.addAttribute("passwordMsg" , map.get("passwordMsg")) ;
            return "/site/login" ;
        }

    }


    @RequestMapping(path = "/logout" , method = RequestMethod.GET)
    public String logout(@CookieValue("ticket") String ticket){
        userService.logout(ticket);
        // 退出之后，清理权限
        SecurityContextHolder.clearContext();
        return "redirect:/login" ;
    }


    @RequestMapping(path = "/forget" , method = RequestMethod.GET)
    public String getForgetPage(){
        return "/site/forget" ;
    }


    // 通过邮箱获取验证码
    // 目的是测试该邮箱可用
    @RequestMapping(path = "/forget/code" , method = RequestMethod.GET)
    @ResponseBody
    public String getForgetCode(String email , HttpSession session){
        if(StringUtils.isBlank(email)){
            return CommunityUtil.getJSONString(1 , "邮箱不能为空!") ;
        }
        // 这里应该验证一下邮箱合法性
        User user = userService.findUserByEmail(email);
        if(user == null){
            return CommunityUtil.getJSONString(1,"该邮箱未注册!") ;
        }


        Context context = new Context() ;
        context.setVariable("email" , email);
        String code = CommunityUtil.generateUUID().substring(0,4) ;
        context.setVariable("verifyCode" , code);
        String content = templateEngine.process("/mail/forget" , context) ;
        mailClient.sendMail(email , "找回密码" , content);
        session.setAttribute("verifyCode" , code);
        return CommunityUtil.getJSONString(0) ;
    }




    @RequestMapping(path = "/forget/password" , method = RequestMethod.POST)
    public String resetPassword(String email , String verifyCode , String password , Model model ,
                                HttpSession session){
        String code = (String) session.getAttribute("verifyCode") ;
        if(StringUtils.isBlank(verifyCode) || StringUtils.isBlank(code) || !code.equalsIgnoreCase(verifyCode)){
            model.addAttribute("codeMsg" , "验证码错误!") ;
            return "/site/forget" ;
        }

        // 验证码通过，可以修改密码
        Map<String , Object> map = userService.resetPassword(email ,password ) ;
        if(map.containsKey("user")){
            return "redirect:/login" ;
        }else {
            model.addAttribute("emailMsg" , map.get("emailMsg")) ;
            model.addAttribute("passwordMsg" , map.get("passwordMsg")) ;
            return "/site/forget" ;
        }

    }



}
